<template>
  <div class="container">
    <h3>vue+openlayers：绘制正方形、矩形、六芒星</h3>
    <div>
      <el-select v-model="tool">
        <el-option v-for="item in tools" :key="item.value" :value="item.value" :label="item.label" />
      </el-select>
    </div>
    <div id="vue-openlayers"></div>
  </div>
</template>

<script>
import 'ol/ol.css'
import { Map, View } from 'ol'
import Tile from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import LayerVector from 'ol/layer/Vector' // 矢量图层
import SourceVector from 'ol/source/Vector' // 矢量数据源
import Draw, { createRegularPolygon, createBox } from 'ol/interaction/Draw' // 绘制交互 createRegularPolygon: 绘制正多边形 createBox: 绘制矩形
import Polygon from 'ol/geom/Polygon' // 多边形
import Fill from 'ol/style/Fill' // 填充样式
import Stroke from 'ol/style/Stroke' // 边界样式
import Style from 'ol/style/Style' // 样式
import { Circle } from 'ol/style' // 圆形样式
export default {
  data() {
    return {
      tool: 'Square', // 绘制类型
      tools: [
        { value: 'Square', label: '正方形' },
        { value: 'Rectangle', label: '矩形' },
        { value: 'Hexagram', label: '六芒星' },
        { value: 'None', label: '无' }
      ],
      map: null,
      draw: null, // 绘制对象
      source: new SourceVector({
        wrapX: false // 不允许x轴方向重复
      })
    }
  },
  watch: {
    tool(newVal) {
      this.addInteraction()
    }
  },
  mounted() {
    this.initMap()
  },
  methods: {
    initMap() {
      let raster = new Tile({
        source: new XYZ({
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7'
        })
      })
      let vector = new LayerVector({
        source: this.source,
        // Vector图层样式
        style: new Style({
          fill: new Fill({
            color: '#00f'
          }),
          stroke: new Stroke({
            width: 2,
            color: '#ff0'
          }),
          image: new Circle({
            redius: 5,
            fill: new Fill({
              color: '#ff0000'
            })
          })
        })
      })

      this.map = new Map({
        target: 'vue-openlayers',
        layers: [raster, vector],
        view: new View({
          projection: 'EPSG:4326',
          center: [116.397411, 39.909186],
          zoom: 10
        })
      })
      this.addInteraction()
    },

    // 添加绘制交互
    addInteraction() {
      if(this.draw) {
        this.map.removeInteraction(this.draw)
      }
      if (this.tool !== 'None') {
        let geometryFunction
        let type = 'Circle'
        if (this.tool === 'Square') {
          // 正方形
          geometryFunction = createRegularPolygon(4)
        } else if (this.tool === 'Hexagram') {
          // 六芒星
          geometryFunction = function(coordinates, geometry) {
            // 中心点
            let center = coordinates[0]
            // 鼠标点击的另一个点
            let last = coordinates[1]
            // 半径
            let dx = center[0] - last[0]
            let dy = center[1] - last[1]
            let radius = Math.sqrt(dx * dx + dy * dy)
            // 角度
            let rotation = Math.atan2(dy, dx)
            // 用来记录顶点坐标的数组
            let newCoordinates = []
            // 顶点数
            let numPoints = 12
            // 顶点坐标
            for (let i = 0; i < numPoints; ++i) {
              let angle = rotation + (i * 2 * Math.PI) / numPoints
              let fraction = i % 2 === 0 ? 1 : 0.5
              let offsetX = radius * fraction * Math.cos(angle)
              let offsetY = radius * fraction * Math.sin(angle)
              newCoordinates.push([center[0] + offsetX, center[1] + offsetY])
            }
            newCoordinates.push(newCoordinates[0].slice()) // 闭合
            if (!geometry) {
              geometry = new Polygon([newCoordinates]) // 绘制多边形
            } else {
              geometry.setCoordinates([newCoordinates]) // 修改多边形
            }
            return geometry
          }
        } else if (this.tool === 'Rectangle') {
          // 矩形
          type = 'Circle' // 为什么要设置为圆形，因为矩形是圆形的特殊形式
          geometryFunction = createBox()
        }

        this.draw = new Draw({
          source: this.source,
          type,
          geometryFunction
        })
        this.map.addInteraction(this.draw)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.container {
    width: 840px;
    height: 550px;
    margin: 50px auto;
    border: 1px solid #ccc;
    #vue-openlayers {
      width: 800px;
      height: 420px;
      margin: 0 auto;
      border: 1px solid #42b983;
      position: relative;
    }
  }
</style>
